package cn.com.twoke.easyproject.config.version;

import cn.hutool.core.lang.Opt;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;

public class ApiVersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {


    @Override
    protected boolean isHandler(Class<?> beanType) {
        return super.isHandler(beanType);
    }

    @Override
    protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
        ApiVersion apiVersion = handlerType.getAnnotation(ApiVersion.class);
        return  null == apiVersion ? super.getCustomTypeCondition(handlerType) : new ApiVersionCondition(
                apiVersion.value(), apiVersion.accessPolicy());
    }

    @Override
    protected RequestCondition<?> getCustomMethodCondition(Method method) {
        ApiVersion apiVersion = method.getAnnotation(ApiVersion.class);
        return  null == apiVersion ? super.getCustomMethodCondition(method) : new ApiVersionCondition(apiVersion.value()
                , apiVersion.accessPolicy());
    }

    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo originInfo = super.getMappingForMethod(method, handlerType);
        if (originInfo == null) {
            return null;
        }
        ApiVersion apiVersion = AnnotationUtils.getAnnotation(handlerType, ApiVersion.class);
        ApiVersion methodVersion =  AnnotationUtils.getAnnotation(method, ApiVersion.class);
        if (methodVersion != null) {
            apiVersion = methodVersion;
        }
        if (apiVersion == null) {
            return originInfo;
        }
        ApiVersionType apiVersionType =
                Opt.ofNullable(apiVersion).map(ApiVersion::type)
                        .orElse(ApiVersionType.STATIC);
        return RequestMappingInfo
                .paths(apiVersionType.path(apiVersion.value()))
                .options(super.getBuilderConfiguration())
                .build().combine(originInfo);
    }
}